/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.filesystems;
import java.io.*;
import java.util.*;
import java.lang.ref.*;
import javax.swing.event.EventListenerList;
import org.openide.TopManager;
import org.openide.util.Utilities;
import org.openide.util.enum.*;
/** Implementation of the file object for abstract file system.
*
* @author Jaroslav Tulach,
*/
final class AbstractFileObject extends AbstractFolder {
/** generated Serialized Version UID */
static final long serialVersionUID = -2343651324897646809L;
/** default extension separator */
private static final char EXT_SEP = '.';
/** default path separator */
private static final char PATH_SEP = '/';
/** Reference to lock or null */
private Reference lock;
/** cache to remember if this object is folder or not */
private Boolean folder;
/** the time of last modification */
private java.util.Date lastModified;
/** Constructor. Takes reference to file system this file belongs to.
*
* @param fs the file system
* @param parent the parent object (folder)
* @param name name of the object (e.g. <code>filename.ext</code>)
*/
public AbstractFileObject (AbstractFileSystem fs, AbstractFileObject parent, String name) {
super (fs, parent, name);
}
/** Getter for the right file system */
private AbstractFileSystem getAbstractFileSystem () {
return (AbstractFileSystem)getFileSystem ();
}
/** Getter for one of children.
*/
private AbstractFileObject getAbstractChild (String name) {
return (AbstractFileObject)getChild (name);
}
//
// List
//
/** Method that allows subclasses to return its children.
*
* @return names (name . ext) of subfiles
*/
protected final String[] list () {
return getAbstractFileSystem ().list.children (toString ());
}
/** Method to create a file object for given subfile.
* @param name of the subfile
* @return the file object
*/
protected final AbstractFolder createFile (String name) {
return getAbstractFileSystem ().createFileObject (this, name);
}
//
// Info
//
/* Test whether this object is a folder.
* @return true if the file object is a folder (i.e., can have children)
*/
public boolean isFolder () {
if (folder == null) {
if (parent == null || getAbstractFileSystem ().info.folder (toString ())) {
folder = Boolean.TRUE;
return true;
} else {
folder = Boolean.FALSE;
return false;
}
} else {
return folder.booleanValue ();
}
}
/* Test whether this object is a data object.
* This is exclusive with {@link #isFolder}.
* @return true if the file object represents data (i.e., can be read and written)
*/
public final boolean isData () {
return !isFolder ();
}
/*
* Get last modification time.
* @return the date
*/
public java.util.Date lastModified() {
if (lastModified == null) {
lastModified = getAbstractFileSystem ().info.lastModified (toString ());
}
return lastModified;
}
/* Test whether this file can be written to or not.
* @return <CODE>true</CODE> if file is read-only
*/
public boolean isReadOnly () {
AbstractFileSystem fs = getAbstractFileSystem ();
return fs.isReadOnly () || fs.info.readOnly (toString ());
}
/* Get the MIME type of this file.
* The MIME type identifies the type of the file's contents and should be used in the same way as in the <B>Java
* Activation Framework</B> or in the {@link java.awt.datatransfer} package.
* <P>
* The default implementation calls {@link FileUtil#getMIMEType}.
*
* @return the MIME type textual representation, e.g. <code>"text/plain"</code>
*/
public String getMIMEType () {
return getAbstractFileSystem ().info.mimeType (toString ());
}
/* Get the size of the file.
* @return the size of the file in bytes or zero if the file does not contain data (does not
* exist or is a folder).
*/
public long getSize () {
return getAbstractFileSystem ().info.size (toString ());
}
/* Get input stream.
* @return an input stream to read the contents of this file
* @exception FileNotFoundException if the file does not exists or is invalid
*/
public InputStream getInputStream () throws java.io.FileNotFoundException {
return getAbstractFileSystem ().info.inputStream (toString ());
}
/* Get output stream.
* @param lock the lock that belongs to this file (obtained by a call to
* {@link #lock})
* @return output stream to overwrite the contents of this file
* @exception IOException if an error occures (the file is invalid, etc.)
*/
public synchronized OutputStream getOutputStream (FileLock lock)
throws java.io.IOException {
testLock (lock);
return new NotifyOutputStream (getAbstractFileSystem ().info.outputStream (toString ()));
}
/* Lock this file.
* @return lock that can be used to perform various modifications on the file
* @throws FileAlreadyLockedException if the file is already locked
*/
public synchronized FileLock lock () throws IOException {
if (lock != null) {
FileLock f = (FileLock)lock.get ();
if (f != null) {
// System.out.println ("Already locked: " + this); // NOI18N
throw new FileAlreadyLockedException();
}
}
getAbstractFileSystem ().info.lock (toString ());
FileLock l = new AfLock ();
lock = new WeakReference (l);
// Thread.dumpStack ();
// System.out.println ("Locking file: " + this); // NOI18N
return l;
}
/** Unlocks the file. Notifies the underlaying impl.
*/
synchronized void unlock () {
getAbstractFileSystem ().info.unlock (toString ());
lastModified = getAbstractFileSystem ().info.lastModified (toString ());
// clear my lock
lock = null;
}
/** Tests the lock if it is valid, if not throws exception.
* @param l lock to test
*/
private void testLock (FileLock l) throws java.io.IOException {
if (lock == null || lock.get () != l) {
FSException.io ("EXC_InvalidLock", toString (), getAbstractFileSystem ().getDisplayName ()); // NOI18N
}
}
// [???] Implicit file state is important.
/* Indicate whether this file is important from a user perspective.
* This method allows a file system to distingush between important and
* unimportant files when this distinction is possible.
* <P>
* <em>For example:</em> Java sources have important <code>.java</code> files and
* unimportant <code>.class</code> files. If the file system provides
* an "archive" feature it should archive only <code>.java</code> files.
* @param b true if the file should be considered important
*/
public void setImportant (boolean b) {
if (!b) {
getAbstractFileSystem ().info.markUnimportant (toString ());
}
}
/* Get the file attribute with the specified name.
* @param attrName name of the attribute
* @return appropriate (serializable) value or <CODE>null</CODE> if the attribute is unset (or could not be properly restored for some reason)
*/
public Object getAttribute(String attrName) {
return getAbstractFileSystem ().attr.readAttribute (toString (), attrName);
}
/* Set the file attribute with the specified name.
* @param attrName name of the attribute
* @param value new value or <code>null</code> to clear the attribute. Must be serializable, although particular file systems may or may not use serialization to store attribute values.
* @exception IOException if the attribute cannot be set. If serialization is used to store it, this may in fact be a subclass such as {@link NotSerializableException}.
*/
public void setAttribute(String attrName, Object value) throws IOException {
getAbstractFileSystem ().attr.writeAttribute (toString (), attrName, value);
}
/* Get all file attribute names for this file.
* @return enumeration of keys (as strings)
*/
public Enumeration getAttributes() {
return getAbstractFileSystem ().attr.attributes (toString ());
}
/* Create a new folder below this one with the specified name. Fires
* <code>fileCreated</code> event.
*
* @param name the name of folder to create (without extension)
* @return the new folder
* @exception IOException if the folder cannot be created (e.g. already exists)
*/
public synchronized FileObject createFolder (String name) throws IOException {
AbstractFileSystem fs = getAbstractFileSystem ();
if (fs.isReadOnly()) {
FSException.io("EXC_FSisRO", fs.getDisplayName ()); // NOI18N
}
if (isReadOnly()) {
FSException.io("EXC_FisRO", name, fs.getDisplayName ()); // NOI18N
}
getAbstractFileSystem ().change.createFolder (toString () + PATH_SEP + name);
refresh (name, null);
AbstractFileObject fo = getAbstractChild (name);
if (fo == null) {
// system error
throw new FileStateInvalidException (FileSystem.getString ("EXC_ApplicationCreateError", toString (), name));
}
if (hasListeners ()) {
fileCreated0(new FileEvent(fo), false);
}
return fo;
}
/* Create new data file in this folder with the specified name. Fires
* <code>fileCreated</code> event.
*
* @param name the name of data object to create (should not contain a period)
* @param ext the extension of the file (or <code>null</code> or <code>""</code>)
*
* @return the new data file object
* @exception IOException if the file cannot be created (e.g. already exists)
*/
public synchronized FileObject createData (String name, String ext) throws IOException {
AbstractFileSystem fs = getAbstractFileSystem ();
if (fs.isReadOnly()) {
FSException.io("EXC_FSisRO", fs.getDisplayName ()); // NOI18N
}
if (isReadOnly()) {
FSException.io("EXC_FisRO", name, fs.getDisplayName ()); // NOI18N
}
String n = "".equals (ext) ? name : name + EXT_SEP + ext; // NOI18N
getAbstractFileSystem ().change.createData (toString () + PATH_SEP + n);
refresh (n, null);
AbstractFileObject fo = getAbstractChild (n);
if (fo == null) {
// system error
throw new FileStateInvalidException (FileSystem.getString ("EXC_ApplicationCreateError", toString (), n));
}
if (hasListeners ()) {
fileCreated0(new FileEvent(fo), true);
}
return fo;
}
/* Renames this file (or folder).
* Both the new basename and new extension should be specified.
* <p>
* Note that using this call, it is currently only possible to rename <em>within</em>
* a parent folder, and not to do moves <em>across</em> folders.
* Conversely, implementing file systems need only implement "simple" renames.
* If you wish to move a file across folders, you should call {@link FileUtil#moveFile}.
* @param lock File must be locked before renaming.
* @param name new basename of file
* @param ext new extension of file (ignored for folders)
*/
public void rename(FileLock lock, String name, String ext) throws IOException {
if (parent == null) {
FSException.io ("EXC_CannotRenameRoot", getAbstractFileSystem ().getDisplayName ()); // NOI18N
}
if (name == null) {
throw new NullPointerException();
}
synchronized (parent) {
// synchronize on your folder
testLock (lock);
if (isData ()) {
if (ext == null) {
throw new NullPointerException();
}
name = name + EXT_SEP + ext;
}
String newFullName = parent.toString () + PATH_SEP + name;
String oldFullName = toString ();
if (isReadOnly ()) {
FSException.io ("EXC_CannotRename", toString (), getAbstractFileSystem ().getDisplayName (), newFullName); // NOI18N
}
if (getFileSystem ().isReadOnly()) {
FSException.io ("EXC_FSisRO", getAbstractFileSystem ().getDisplayName ()); // NOI18N
}
String on = getName ();
String oe = getExt ();
getAbstractFileSystem ().change.rename (oldFullName, newFullName);
String oldName = this.name;
this.name = name;
// clear cached full name
this.fullName = null;
/*
System.out.println ("Resulting file is: " + toString ());
System.out.println ("Bedw file is: " + newFullName);
System.out.println ("Name: " + name);
System.out.println ("Old : " + oldName);
*/
parent.refresh (name, oldName);
getAbstractFileSystem ().attr.renameAttributes (oldFullName, newFullName);
if (hasAtLeastOneListeners ()) {
fileRenamed0 (new FileRenameEvent(this, on, oe));
}
}
}
/* Delete this file. If the file is a folder and it is not empty then
* all of its contents are also recursively deleted.
*
* @param lock the lock obtained by a call to {@link #lock}
* @exception IOException if the file could not be deleted
*/
public void delete (FileLock lock) throws IOException {
if (parent == null) {
FSException.io ("EXC_CannotDeleteRoot", getAbstractFileSystem ().getDisplayName ()); // NOI18N
}
synchronized (parent) {
testLock (lock);
String fullName = toString ();
getAbstractFileSystem ().change.delete (fullName);
String n = name;
// if deleted set systemName to null, that indicates that
// the object is not valid
systemName = null;
parent.refresh (null, n);
getAbstractFileSystem ().attr.deleteAttributes (fullName);
if (hasAtLeastOneListeners ()) {
fileDeleted0(new FileEvent(this));
}
}
}
//
// Transfer
//
/** Copies this file. This allows the filesystem to perform any additional
* operation associated with the copy. But the default implementation is simple
* copy of the file and its attributes
*
* @param target target folder to move this file to
* @param name new basename of file
* @param ext new extension of file (ignored for folders)
* @return the newly created file object representing the moved file
*/
public FileObject copy (FileObject target, String name, String ext)
throws IOException {
AbstractFileSystem fs = getAbstractFileSystem ();
AbstractFileSystem.Transfer from = getAbstractFileSystem ().transfer;
if (from == null || !(target instanceof AbstractFileObject)) {
return super.copy (target, name, ext);
}
AbstractFileObject abstractTarget = (AbstractFileObject)target;
AbstractFileSystem abstractFS = abstractTarget.getAbstractFileSystem ();
AbstractFileSystem.Transfer to = abstractFS.transfer;
if (to != null) synchronized (abstractTarget) {
// try copying thru the transfer
if (abstractFS.isReadOnly()) {
FSException.io ("EXC_FSisRO", abstractFS.getDisplayName ()); // NOI18N
}
if (target.isReadOnly()) {
FSException.io ("EXC_FisRO", target.toString (), abstractFS.getDisplayName ()); // NOI18N
}
String n = "".equals (ext) ? name : name + EXT_SEP + ext; // NOI18N
if (from.copy (toString (), to, target.toString () + PATH_SEP + n)) {
// the transfer implementation thinks that the copy succeeded
abstractTarget.refresh (n, null);
AbstractFileObject fo = abstractTarget.getAbstractChild (n);
if (fo == null) {
// system error
throw new FileStateInvalidException (FileSystem.getString ("EXC_ApplicationCreateError", abstractTarget.toString (), n));
}
if (abstractTarget.hasListeners ()) {
abstractTarget.fileCreated0(new FileEvent(fo), true);
}
return fo;
}
}
return super.copy (target, name, ext);
}
/** Moves this file. This allows the filesystem to perform any additional
* operation associated with the move. But the default implementation is encapsulated
* as copy and delete.
*
* @param lock File must be locked before renaming.
* @param target target folder to move this file to
* @param name new basename of file
* @param ext new extension of file (ignored for folders)
* @return the newly created file object representing the moved file
*/
public FileObject move (FileLock lock, FileObject target, String name, String ext)
throws IOException {
AbstractFileSystem fs = getAbstractFileSystem ();
if (parent == null) {
FSException.io ("EXC_CannotDeleteRoot", fs.getDisplayName ()); // NOI18N
}
AbstractFileSystem.Transfer from = getAbstractFileSystem ().transfer;
if (from == null || !(target instanceof AbstractFileObject)) {
return super.move (lock, target, name, ext);
}
AbstractFileObject abstractTarget = (AbstractFileObject)target;
AbstractFileSystem abstractFS = abstractTarget.getAbstractFileSystem ();
AbstractFileSystem.Transfer to = abstractFS.transfer;
if (to != null) synchronized (parent) {
testLock (lock);
if (abstractFS.isReadOnly()) {
FSException.io ("EXC_FSisRO", abstractFS.getDisplayName ()); // NOI18N
}
if (target.isReadOnly()) {
FSException.io ("EXC_FisRO", target.toString (), abstractFS.getDisplayName ()); // NOI18N
}
String n = "".equals (ext) ? name : name + EXT_SEP + ext; // NOI18N
String fullName = toString ();
if (from.move (fullName, to, target.toString () + PATH_SEP + n)) {
// the transfer implementation thinks that the move succeeded
String oldN = name;
// if deleted set systemName to null, that indicates that
// the object is not valid
systemName = null;
// refresh the parent because this file has been deleted
parent.refresh (null, oldN);
// deletes all attributes asssociated with the moved file
// JST: I am not sure if this is the right behaviour, maybe this
// should be the reposibility of from.move?
// fs.attr.deleteAttributes (fullName);
// refresh the target so new file appears there
abstractTarget.refresh (n, null);
AbstractFileObject fo = abstractTarget.getAbstractChild (n);
if (fo == null) {
// system error
throw new FileStateInvalidException (FileSystem.getString ("EXC_ApplicationCreateError", abstractTarget.toString (), n));
}
if (hasAtLeastOneListeners ()) {
fileDeleted0(new FileEvent(this));
}
if (abstractTarget.hasListeners ()) {
abstractTarget.fileCreated0(new FileEvent(fo), true);
}
return fo;
}
}
return super.move (lock, target, name, ext);
}
/** Refresh the content of file. Ignores changes to the files provided,
* instead returns its file object.
* @param added do not notify addition of this file
* @param removed do not notify removing of this file
* @param fire true if we should fire changes
*/
protected synchronized void refresh (
String added, String removed, boolean fire, boolean expected
) {
if (isFolder ()) {
super.refresh (added, removed, fire, expected);
} else {
// check the time of a file last modification
if (fire) {
java.util.Date l = getAbstractFileSystem ().info.lastModified (toString ());
if (lastModified == null) {
lastModified = l;
return;
}
// JST: Seems like the lastModified () time can vary a bit on NT (up to 500ms)
// if (!l.equals (lastModified)) {
//
if (Math.abs(lastModified.getTime() - l.getTime ()) >= 5000) {
/*
System.out.println("file : " + toString ());
System.out.println("prev date: " + lastModified.getTime ());
System.out.println("now date: " + l.getTime());
System.out.println("diff : " + (lastModified.getTime () - l.getTime()));
*/
lastModified = l;
if (hasAtLeastOneListeners ()) {
FileEvent ev = new FileEvent (this, this);
ev.setExpected (expected);
fileChanged0 (ev);
}
}
}
}
// System.out.println ("Refresh of " + this + " ended"); // NOI18N
return;
}
/** Implementation of lock for abstract files.
*/
private class AfLock extends FileLock {
public void releaseLock () {
if (this.isValid()) {
super.releaseLock();
unlock ();
}
}
}
//
// Invalid object that can be created after deserialization
//
static final class Invalid extends FileObject {
static final long serialVersionUID =-4558997829579415276L;
/** name */
private String name;
private String fullName;
/** special instance that represent root */
private static final Invalid ROOT = new Invalid (""); // NOI18N
/** Constructor. Takes reference to file system this file belongs to.
*
* @param fs file system
* @param parent the parent object
* @param name name of the object
*/
public Invalid (String name) {
fullName = name;
int i = name.lastIndexOf ('/') + 1;
this.name = i == 0 || i == name.length () ? name : name.substring (i);
}
/** Get the name without extension of this file.
*
* @return name of the file (in its enclosing folder)
*/
public String getName () {
int i = name.lastIndexOf ('.');
return i == -1 ? name : name.substring (0, i);
}
/** Get the extension of this file.
* This is the string after the last dot of the full name, if any.
*
* @return extension of the file (if any) or empty string if there is none
*/
public String getExt () {
int i = name.lastIndexOf ('.') + 1;
return i == 0 || i == name.length () ? "" : name.substring (i); // NOI18N
}
/** @exception FileStateInvalidException always
*/
public FileSystem getFileSystem () throws FileStateInvalidException {
throw new FileStateInvalidException ();
}
//
// Info
//
/** Test whether this object is the root folder.
* The root should always be a folder.
* @return true if the object is the root of a file system
*/
public boolean isRoot () {
return this == ROOT;
}
/** Test whether this object is a folder.
* @return true if the file object is a folder (i.e., can have children)
*/
public boolean isFolder () {
return this == ROOT;
}
/**
* Get last modification time.
* @return the date
*/
public java.util.Date lastModified() {
return new java.util.Date ();
}
/** Test whether this object is a data object.
* This is exclusive with {@link #isFolder}.
* @return true if the file object represents data (i.e., can be read and written)
*/
public boolean isData () {
return false;
}
/** Test whether this file can be written to or not.
* @return <CODE>true</CODE> if file is read-only
*/
public boolean isReadOnly () {
return false;
}
/** Test whether the file is valid. The file can be invalid if it has been deserialized
* and the file no longer exists on disk; or if the file has been deleted.
*
* @return true if the file object is valid
*/
public boolean isValid () {
return false;
}
/** Get the MIME type of this file.
* The MIME type identifies the type of the file's contents and should be used in the same way as in the <B>Java
* Activation Framework</B> or in the {@link java.awt.datatransfer} package.
* <P>
* The default implementation calls {@link FileUtil#getMIMEType}.
*
* @return the MIME type textual representation, e.g. <code>"text/plain"</code>
*/
public String getMIMEType () {
return "content/unknown"; // NOI18N
}
/** Get the size of the file.
* @return the size of the file in bytes or zero if the file does not contain data (does not
* exist or is a folder).
*/
public long getSize () {
return 0;
}
/** Get input stream.
* @return an input stream to read the contents of this file
* @exception FileNotFoundException if the file does not exists or is invalid
*/
public InputStream getInputStream () throws java.io.FileNotFoundException {
throw new java.io.FileNotFoundException ();
}
/** Get output stream.
* @param lock the lock that belongs to this file (obtained by a call to
* {@link #lock})
* @return output stream to overwrite the contents of this file
* @exception IOException if an error occures (the file is invalid, etc.)
*/
public synchronized OutputStream getOutputStream (FileLock lock)
throws java.io.IOException {
throw new java.io.IOException ();
}
/** Lock this file.
* @return lock that can be used to perform various modifications on the file
* @throws FileAlreadyLockedException if the file is already locked
*/
public synchronized FileLock lock () throws IOException {
throw new java.io.IOException ();
}
/** Indicate whether this file is important from a user perspective.
* This method allows a file system to distingush between important and
* unimportant files when this distinction is possible.
* <P>
* <em>For example:</em> Java sources have important <code>.java</code> files and
* unimportant <code>.class</code> files. If the file system provides
* an "archive" feature it should archive only <code>.java</code> files.
* @param b true if the file should be considered important
*/
public void setImportant (boolean b) {
}
/** Get the file attribute with the specified name.
* @param attrName name of the attribute
* @return appropriate (serializable) value or <CODE>null</CODE> if the attribute is unset (or could not be properly restored for some reason)
*/
public Object getAttribute(String attrName) {
return null;
}
/** Set the file attribute with the specified name.
* @param attrName name of the attribute
* @param value new value or <code>null</code> to clear the attribute. Must be serializable, although particular file systems may or may not use serialization to store attribute values.
* @exception IOException if the attribute cannot be set. If serialization is used to store it, this may in fact be a subclass such as {@link NotSerializableException}.
*/
public void setAttribute(String attrName, Object value) throws IOException {
throw new java.io.IOException ();
}
/** Get all file attribute names for this file.
* @return enumeration of keys (as strings)
*/
public Enumeration getAttributes() {
return EmptyEnumeration.EMPTY;
}
/** Create a new folder below this one with the specified name. Fires
* <code>fileCreated</code> event.
*
* @param name the name of folder to create (without extension)
* @return the new folder
* @exception IOException if the folder cannot be created (e.g. already exists)
*/
public synchronized FileObject createFolder (String name) throws IOException {
throw new java.io.IOException ();
}
/** Create new data file in this folder with the specified name. Fires
* <code>fileCreated</code> event.
*
* @param name the name of data object to create (should not contain a period)
* @param ext the extension of the file (or <code>null</code> or <code>""</code>)
*
* @return the new data file object
* @exception IOException if the file cannot be created (e.g. already exists)
*/
public synchronized FileObject createData (String name, String ext) throws IOException {
throw new java.io.IOException ();
}
/** Renames this file (or folder).
* Both the new basename and new extension should be specified.
* <p>
* Note that using this call, it is currently only possible to rename <em>within</em>
* a parent folder, and not to do moves <em>across</em> folders.
* Conversely, implementing file systems need only implement "simple" renames.
* If you wish to move a file across folders, you should call {@link FileUtil#moveFile}.
* @param lock File must be locked before renaming.
* @param name new basename of file
* @param ext new extension of file (ignored for folders)
*/
public void rename(FileLock lock, String name, String ext) throws IOException {
throw new java.io.IOException ();
}
/** Delete this file. If the file is a folder and it is not empty then
* all of its contents are also recursively deleted.
*
* @param lock the lock obtained by a call to {@link #lock}
* @exception IOException if the file could not be deleted
*/
public void delete (FileLock lock) throws IOException {
throw new java.io.IOException ();
}
//
// List
//
/** Get parent folder.
* The returned object will satisfy {@link #isFolder}.
*
* @return common root for all invalid objects
*/
public FileObject getParent () {
return this == ROOT ? null : ROOT;
}
/** Get all children of this folder (files and subfolders). If the file does not have children
* (does not exist or is not a folder) then an empty array should be returned. No particular order is assumed.
*
* @return array of direct children
* @see #getChildren(boolean)
* @see #getFolders
* @see #getData
*/
public synchronized FileObject[] getChildren () {
return new FileObject[0];
}
/** Retrieve file contained in this folder by name.
* <em>Note</em> that no file is created on disk.
* @param name basename of the file (in this folder)
* @param ext extension of the file; <CODE>null</CODE> or <code>""</code>
* if the file should have no extension
* @return the object representing this file or <CODE>null</CODE> if the file
* does not exist
* @exception IllegalArgumentException if <code>this</code> is not a folder
*/
public synchronized FileObject getFileObject (String name, String ext) {
return null;
}
/** Refresh the contents of a folder. Rescans the list of children names.
*/
public void refresh() {
}
//
// Listeners section
//
/** Add new listener to this object.
* @param l the listener
*/
public void addFileChangeListener (FileChangeListener fcl) {
}
/** Remove listener from this object.
* @param l the listener
*/
public void removeFileChangeListener (FileChangeListener fcl) {
}
} // end of Invalid
/** Replace that stores name of fs and file.
*/
static final class Replace extends Object implements java.io.Serializable {
/** generated Serialized Version UID */
static final long serialVersionUID = -8543432135435542113L;
private String fsName;
private String fileName;
/** Constructor
*/
public Replace (String fsName, String fileName) {
this.fsName = fsName;
this.fileName = fileName;
}
/** Finds the right file.
*/
public Object readResolve () {
Repository rep = TopManager.getDefault ().getRepository ();
FileSystem fs = rep.findFileSystem (fsName);
FileObject fo = null;
if (fs != null) {
// scan desired system
fo = fs.findResource (fileName);
}
if (fo == null) {
// scan all systems
fo = rep.findResource (fileName);
}
if (fo == null) {
// create invalid file instead
return new Invalid (fileName);
}
return fo;
}
} // end of Replace
}
/*
* Log
* 35 Gandalf-post-FCS1.33.3.0 3/29/00 Svatopluk Dedic Now throws
* NullPointerException if name or ext (in case of files) is null instead
* of renaming to whatever.null
* 34 src-jtulach1.33 1/13/00 Ian Formanek NOI18N
* 33 src-jtulach1.32 1/12/00 Ian Formanek NOI18N
* 32 src-jtulach1.31 1/5/00 Jaroslav Tulach AbstractFileSystem.refreshResource
* modifies lastModified time
* 31 src-jtulach1.30 12/30/99 Jaroslav Tulach New dialog for
* notification of exceptions.
* 30 src-jtulach1.29 11/3/99 Jaroslav Tulach File is modified if the
* difference is more than 5s.
* 29 src-jtulach1.28 11/2/99 Jaroslav Tulach Added comments to see
* why a file is modified.
* 28 src-jtulach1.27 10/29/99 Jaroslav Tulach MultiFileSystem +
* FileStatusEvent
* 27 src-jtulach1.26 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 26 src-jtulach1.25 10/5/99 Miloslav Metelka close() fires only once
* 25 src-jtulach1.24 10/1/99 Jaroslav Tulach FileObject.move &
* FileObject.copy
* 24 src-jtulach1.23 9/27/99 Miloslav Metelka patched releaseLock()
* 23 src-jtulach1.22 9/25/99 Jaroslav Tulach Works copying of files
* without extension.
* 22 src-jtulach1.21 9/17/99 Miloslav Metelka super.releaseLock() in
* lock()
* 21 src-jtulach1.20 9/3/99 Jaroslav Tulach #3320
* 20 src-jtulach1.19 8/31/99 Pavel Buzek
* 19 src-jtulach1.18 8/18/99 Jaroslav Tulach Handles folders with
* dots.
* 18 src-jtulach1.17 8/17/99 Ian Formanek Generated serial version
* UID
* 17 src-jtulach1.16 8/2/99 Jaroslav Tulach Invalid files after
* serialization also have root.
* 16 src-jtulach1.15 7/20/99 Jesse Glick Filenames with multiple
* dots should use last one for extension.
* 15 src-jtulach1.14 7/20/99 Jaroslav Tulach Not valid file system
* has not children.
* 14 src-jtulach1.13 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 13 src-jtulach1.12 6/3/99 Jaroslav Tulach Refresh of only opened
* files.
* 12 src-jtulach1.11 5/24/99 Jaroslav Tulach
* 11 src-jtulach1.10 5/17/99 Jaroslav Tulach Even after delete the
* name is valid.
* 10 src-jtulach1.9 5/6/99 Jaroslav Tulach Survives when root of FS
* is deleted.
* 9 src-jtulach1.8 4/9/99 Jaroslav Tulach
* 8 src-jtulach1.7 4/7/99 Petr Hamernik Find works (once more) -
* bugfix
* 7 src-jtulach1.6 3/27/99 Jaroslav Tulach Find work.
* 6 src-jtulach1.5 3/26/99 Jesse Glick [JavaDoc]
* 5 src-jtulach1.4 3/26/99 Jaroslav Tulach
* 4 src-jtulach1.3 3/26/99 Jaroslav Tulach Refresh & Bundles
* 3 src-jtulach1.2 3/26/99 Jaroslav Tulach
* 2 src-jtulach1.1 3/26/99 Jaroslav Tulach
* 1 src-jtulach1.0 3/24/99 Jaroslav Tulach
* $
* Beta Change History:
* 0 Tuborg 0.32 --/--/98 Petr Hamernik isReadOnly, rename methods added
* 0 Tuborg 0.33 --/--/98 Petr Hamernik getURL added
* 0 Tuborg 0.34 --/--/98 Jaroslav Tulach getURL made final
* 0 Tuborg 0.35 --/--/98 Petr Hamernik lock throws IOException
* 0 Tuborg 0.36 --/--/98 Jaroslav Tulach comments extended
* 0 Tuborg 0.38 --/--/98 Petr Hamernik file attributes
* 0 Tuborg 0.39 --/--/98 Petr Hamernik comments improved
* 0 Tuborg 0.40 --/--/98 Jan Formanek equals() and hashCode() added
* 0 Tuborg 0.41 --/--/98 Jaroslav Tulach late fireXYZ methods, only adds to the FS fire queue
* 0 Tuborg 0.42 --/--/98 Petr Hamernik URL protocol
* 0 Tuborg 0.43 --/--/98 Ales Novak NbfsURLConstants
*/